package com.liuqi.knet.rpc.cluster.support;

import com.liuqi.knet.rpc.cluster.ClusterConfig;
import com.liuqi.loggers.api.Logger;
import com.liuqi.loggers.facade.LoggersFacade;
import com.liuqi.knet.remoting.Client;
import com.liuqi.knet.remoting.RemotingException;
import com.liuqi.knet.rpc.cluster.AbstractCluster;
import com.liuqi.knet.rpc.cluster.LoadBalanceNode;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 发送消息失败时, 在重试次数过程中, 通过负载均衡选取器选取下一个节点, 再次发送
 *
 * @author liuqi
 * @date 2024/6/20 10:46
 **/
public class FailoverCluster extends AbstractCluster {

    private final static Logger logger = LoggersFacade.getLogger(FailoverCluster.class);

    private final Lock lock = new ReentrantLock();

    /**
     * 仅保持一个连接
     */
    public final Client[] clients = new Client[1];

    public FailoverCluster(ClusterConfig clusterConfig) {
        super(clusterConfig);
    }

    @Override
    public boolean isActive() {
        return clients[0] != null && clients[0].isActive();
    }

    @Override
    public void connect() throws RemotingException {
        getClient();
    }

    @Override
    public void reconnect() throws RemotingException {
        clients[0].reconnect();
    }

    @Override
    public void close() {
        if (clients[0] != null) {
            try {
                clients[0].close();
            } catch (Throwable t) {
                logger.error(t.getMessage());
            }
        }
        clients[0] = null;
    }

    @Override
    public Client[] clients() {
        if (clients[0] == null) {
            return null;
        } else {
            return clients;
        }
    }

    protected Client getClient() throws RemotingException {
        if (clients[0] != null && clients[0].isActive()) {
            return clients[0];
        }

        lock.lock();
        try {
            LoadBalanceNode.Node node;
            Client newClient;

            try {
                node = getLoadBalance().select();
            } catch (RemotingException e) {
                logger.error("负载均衡获取集群节点发生错误, LoadBalance: [{}], ErrorMsg: [{}]", getLoadBalance(), e.getMessage());
                throw e;
            }

            // 关闭旧的连接
            close();

            try {
                logger.info("集群[FailoverCluster]创建客户端连接: " + node);
                newClient = createClient(node);
                clients[0] = newClient;
                return clients[0];
            } catch (RemotingException e) {
                logger.error("创建客户端失败, ErrorMsg: [{}]", e.getMessage());
                throw e;
            }
        } finally {
            lock.unlock();
        }
    }

}
